﻿using SDL2;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
namespace BITUI.Tile
{


    public static class TileTool
    {
        [ThreadStatic]
        public static SHA256 sha256;

        public static float ToScaleValue(this Element.TileRenderScale scale)
        {
            switch (scale)
            {
                case Element.TileRenderScale.One:
                    return 1.0f;
                case Element.TileRenderScale.Less1_2:
                    return 0.5f;
                case Element.TileRenderScale.Less1_4:
                    return 0.25f;
                case Element.TileRenderScale.Less1_8:
                    return 0.125f;
                case Element.TileRenderScale.X2:
                    return 2.0f;
                case Element.TileRenderScale.X4:
                    return 4.0f;
                case Element.TileRenderScale.X8:
                    return 8.0f;
                default:
                    return 0;

            }
        }
        public static string ComputeTileDataHash(TileData data)
        {
            if (sha256 == null)
                sha256 = SHA256.Create();

            var bts = data.ToBytes();
            var hash = sha256.ComputeHash(bts);
            StringBuilder sb = new StringBuilder();
            foreach (var b in hash)
            {
                sb.Append(b.ToString("X02"));
            }
            return sb.ToString();
        }
        public static SDL.SDL_Color[] GetNesPalette()
        {

            SDL.SDL_Color[] colors = new SDL.SDL_Color[256];
            System.Func<byte, byte, byte, SDL.SDL_Color> FromRgb = (r, g, b) => new SDL.SDL_Color() { r = r, g = g, b = b, a = 255 };
            colors[0x0] = FromRgb(84, 84, 84);
            colors[0x1] = FromRgb(0, 30, 116);
            colors[0x2] = FromRgb(8, 16, 144);
            colors[0x3] = FromRgb(48, 0, 136);
            colors[0x4] = FromRgb(68, 0, 100);
            colors[0x5] = FromRgb(92, 0, 48);
            colors[0x6] = FromRgb(84, 4, 0);
            colors[0x7] = FromRgb(60, 24, 0);
            colors[0x8] = FromRgb(32, 42, 0);
            colors[0x9] = FromRgb(8, 58, 0);
            colors[0xa] = FromRgb(0, 64, 0);
            colors[0xb] = FromRgb(0, 60, 0);
            colors[0xc] = FromRgb(0, 50, 60);
            colors[0xd] = FromRgb(0, 0, 0);
            colors[0xe] = FromRgb(0, 0, 0);
            colors[0xf] = FromRgb(0, 0, 0);
            colors[0x10] = FromRgb(152, 150, 152);
            colors[0x11] = FromRgb(8, 76, 196);
            colors[0x12] = FromRgb(48, 50, 236);
            colors[0x13] = FromRgb(92, 30, 228);
            colors[0x14] = FromRgb(136, 20, 176);
            colors[0x15] = FromRgb(160, 20, 100);
            colors[0x16] = FromRgb(152, 34, 32);
            colors[0x17] = FromRgb(120, 60, 0);
            colors[0x18] = FromRgb(84, 90, 0);
            colors[0x19] = FromRgb(40, 114, 0);
            colors[0x1a] = FromRgb(8, 124, 0);
            colors[0x1b] = FromRgb(0, 118, 40);
            colors[0x1c] = FromRgb(0, 102, 120);
            colors[0x1d] = FromRgb(0, 0, 0);
            colors[0x1e] = FromRgb(0, 0, 0);
            colors[0x1f] = FromRgb(0, 0, 0);
            colors[0x20] = FromRgb(236, 238, 236);
            colors[0x21] = FromRgb(76, 154, 236);
            colors[0x22] = FromRgb(120, 124, 236);
            colors[0x23] = FromRgb(176, 98, 236);
            colors[0x24] = FromRgb(228, 84, 236);
            colors[0x25] = FromRgb(236, 88, 180);
            colors[0x26] = FromRgb(236, 106, 100);
            colors[0x27] = FromRgb(212, 136, 32);
            colors[0x28] = FromRgb(160, 170, 0);
            colors[0x29] = FromRgb(116, 196, 0);
            colors[0x2a] = FromRgb(76, 208, 32);
            colors[0x2b] = FromRgb(56, 204, 108);
            colors[0x2c] = FromRgb(56, 180, 204);
            colors[0x2d] = FromRgb(60, 60, 60);
            colors[0x2e] = FromRgb(0, 0, 0);
            colors[0x2f] = FromRgb(0, 0, 0);
            colors[0x30] = FromRgb(236, 238, 236);
            colors[0x31] = FromRgb(168, 204, 236);
            colors[0x32] = FromRgb(188, 188, 236);
            colors[0x33] = FromRgb(212, 178, 236);
            colors[0x34] = FromRgb(236, 174, 236);
            colors[0x35] = FromRgb(236, 174, 212);
            colors[0x36] = FromRgb(236, 180, 176);
            colors[0x37] = FromRgb(228, 196, 144);
            colors[0x38] = FromRgb(204, 210, 120);
            colors[0x39] = FromRgb(180, 222, 120);
            colors[0x3a] = FromRgb(168, 226, 144);
            colors[0x3b] = FromRgb(152, 226, 180);
            colors[0x3c] = FromRgb(160, 214, 228);
            colors[0x3d] = FromRgb(160, 162, 160);
            colors[0x3e] = FromRgb(0, 0, 0);
            colors[0x3f] = FromRgb(0, 0, 0);
            for (var i = 0x40; i < 256; i++)
            {
                colors[i] = FromRgb(0, 0, 0);
            }
            //transparent
            colors[0x0d].a = 0;
            return colors;
        }
        public static byte GetNesTransparentColorIndex()
        {
            return 0x0D;
        }
        public static TileData GenBlock()
        {
            var cdata = TileData.Create(ColorBitLen.Bit1, 8, 8);
            cdata.palette.palette[0] = 0x0d;
            cdata.palette.palette[1] = 0x30;
            cdata.tiledata = new byte[8] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
            return cdata;
        }
        public static TileData GenGridTileData()
        {
            //基本初始化
            TileData data = TileData.Create(ColorBitLen.Bit2, 8, 8);

            data.palette.palette[0] = 0x0D;
            data.palette.palette[1] = 0x18;
            data.palette.palette[2] = 0x24;
            data.palette.palette[3] = 0x09;
            for (var y = 0; y < 8; y++)
            {
                for (var x = 0; x < 8; x += 4) //一个字节存四个像素
                {
                    var jump = ((((y / 4) % 2) + (x / 4) % 2) % 2 == 1);
                    var color = jump ? 1 : 2;

                    var color1 = jump ? 1 : 2;
                    var color2 = color;
                    var color3 = color1;
                    var outbyte = (color << 6) | (color1 << 4) | (color2 << 2) | (color3 << 0);

                    data.tiledata[y * 2 + x / 4] = (byte)outbyte;
                }
            }
            return data;
        }
        public static TileData GenOneColorTileData(byte colorIndex, byte colorTran = 0x0D)
        {
            TileData data = TileData.Create(ColorBitLen.Bit1, 8, 8);
            data.palette.palette[0] = colorTran;
            data.palette.palette[1] = colorIndex;
            var linedata = new byte[] { 1, 1, 1, 1, 1, 1, 1, 1 };
            for (var y = 0; y < 8; y++)
                data.SetLine(y, linedata);
            return data;
        }
        public static TileData GenOnePixelBorder(bool left, bool top, bool right, bool bottom, byte colorIndex = 0x30, byte colorTran = 0x0D)
        {
            TileData data = TileData.Create(ColorBitLen.Bit1, 8, 8);
            data.palette.palette[0] = colorTran;
            data.palette.palette[1] = colorIndex;
            data.SetLine(0, new bool[] { left || top, top, top, top, top, top, top, top || right });
            data.SetLine(1, new bool[] { left, false, false, false, false, false, false, right });
            data.SetLine(2, new bool[] { left, false, false, false, false, false, false, right });
            data.SetLine(3, new bool[] { left, false, false, false, false, false, false, right });
            data.SetLine(4, new bool[] { left, false, false, false, false, false, false, right });
            data.SetLine(5, new bool[] { left, false, false, false, false, false, false, right });
            data.SetLine(6, new bool[] { left, false, false, false, false, false, false, right });
            data.SetLine(7, new bool[] { left || bottom, bottom, bottom, bottom, bottom, bottom, bottom, right || bottom });

            return data;
        }
        public static TileData GenTwoPixelBorder(bool left, bool top, bool right, bool bottom, byte colorIndex = 0x30, byte colorTran = 0x0D)
        {
            TileData data = TileData.Create(ColorBitLen.Bit1, 8, 8);
            data.palette.palette[0] = colorTran;
            data.palette.palette[1] = colorIndex;
            bool lt = left || top;
            bool rt = right || top;
            bool lb = left || bottom;
            bool rb = right || bottom;
            bool l_ = left;
            bool r_ = right;
            bool _t = top;
            bool _b = bottom;
            bool __ = false;
            bool txl = top & !left;
            bool lxt = left & !top;
            bool txr = top & !right;
            bool rxt = right & !top;
            bool bxl = bottom & !left;
            bool lxb = left & !bottom;
            bool bxr = bottom & !right;
            bool rxb = right & !bottom;
            data.SetLine(0, new bool[] { lt, _t, lt, _t, _t, rt, _t, rt });
            data.SetLine(1, new bool[] { l_, __, lxt, __, __, rxt, __, r_ });
            data.SetLine(2, new bool[] { lt, txl, lt, _t, _t, rt, txr, rt });
            data.SetLine(3, new bool[] { l_, __, l_, __, __, r_, __, r_ });
            data.SetLine(4, new bool[] { l_, __, l_, __, __, r_, __, r_ });
            data.SetLine(5, new bool[] { lb, bxl, lb, _b, _b, rb, bxr, rb });
            data.SetLine(6, new bool[] { l_, __, lxb, __, __, rxb, __, r_ });
            data.SetLine(7, new bool[] { lb, _b, lb, _b, _b, rb, _b, rb });

            return data;
        }
        public static RenderTile LoadBlock(Bank bank)
        {
            var old = bank.GetTileByName("block");
            if (old != null)
                return old;
            return bank.CreateTile("block", GenBlock());
        }
        public static void LoadASCII12toBank(Bank bank)
        {
            byte[] data = System.IO.File.ReadAllBytes("resources/ASC12");

            for (var i = 32; i < 127; i++)
            {
                var cdata = TileData.Create(ColorBitLen.Bit1, 6, 12);
                cdata.palette.palette[0] = 0x0d;
                cdata.palette.palette[1] = 0x30;
                cdata.tiledata = new byte[12];
                for (var j = 0; j < 12 - 1; j++)//向下移动一个像素 ，ASCII 12 英文字体比较小，移动一下，整齐一些
                {
                    cdata.tiledata[j + 1] = data[(i - 32) * 12 + j];
                }
                //bank.CreateTile(((char)i).ToString(), cdata);
                bank.RegTileData(((char)i).ToString(), cdata);
            }

            //放入12点阵光标 
            {
                var cdata = TileData.Create(ColorBitLen.Bit1, 6, 12);
                cdata.palette.palette[0] = 0x0d;
                cdata.palette.palette[1] = 0x30;
                cdata.tiledata = new byte[12];
                for (var i = 0; i < 12; i++)
                {
                    var line = new byte[8];//setLine函数，要求字节对齐
                    line[0] = 1;
                    cdata.SetLine(i, line);
                }
                //光标特别命名很独特
                bank.RegTileData("cursor", cdata);
            }

        }
        public static void LoadHZK12toBank(Bank bank)
        {
            byte[] mapdata = System.IO.File.ReadAllBytes("resources/UTF16CONV");
            Dictionary<UInt16, char> mapGB2Utf16 = new Dictionary<ushort, char>();
            for (var i = 0; i < mapdata.Length / 4; i++)
            {
                var key = (UInt16)(mapdata[i * 4 + 0] + mapdata[i * 4 + 1] * 256);
                var value = (char)(mapdata[i * 4 + 2] + mapdata[i * 4 + 3] * 256);
                mapGB2Utf16[key] = value;
            }
            //FOR GB2312
            //Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            byte[] data = System.IO.File.ReadAllBytes("resources/HZK12");

            //List<byte> mapGB2Utf16 = new List<byte>();
            int charcount = 0;
            var areacount = data.Length / 24 / 94;

            List<byte> savemap = new List<byte>();

            for (var iQu = 0; iQu < 94; iQu++)
            {
                for (var iWei = 0; iWei < 94; iWei++)
                {
                    var cdata = TileData.Create(ColorBitLen.Bit1, 12, 12);
                    cdata.palette.palette[0] = 0x0d;
                    cdata.palette.palette[1] = 0x30;
                    cdata.tiledata = new byte[24];


                    var istart = (iQu * 94 + iWei) * 24;//从这里开始，24个字节
                    if (istart + 24 > data.Length) break;
                    bool allzero = true;
                    for (var k = 0; k < 24; k++)
                    {
                        cdata.tiledata[k] = data[istart + k];
                        if (cdata.tiledata[k] != 0)
                            allzero = false;
                    }
                    if (allzero)
                    {
                        continue;
                    }
                    byte[] gbcode = new byte[2];
                    gbcode[0] = (byte)(0xa1 + iQu);
                    gbcode[1] = (byte)(0xa1 + iWei);
                    var key = (ushort)(gbcode[1] * 256 + gbcode[0]);
                    var hz = mapGB2Utf16[key].ToString();
                    //save map file
                    //因为GB2312编码器默认不可用，所以用个mapfile 干掉他
                    //var hz2 = System.Text.Encoding.GetEncoding("GB2312").GetString(gbcode);
                    //if (hz2.Length > 1)
                    //    continue;
                    //var hzdata = System.Text.Encoding.Unicode.GetBytes(hz2);
                    //savemap.Add(gbcode[0]);
                    //savemap.Add(gbcode[1]);
                    //savemap.Add(hzdata[0]);
                    //savemap.Add(hzdata[1]);

                    bank.RegTileData(hz, cdata);
                    //bank.CreateTile(hz, cdata);
                    charcount++;

                }
            }


            //放入12点阵光标 
            {
                var cdata = TileData.Create(ColorBitLen.Bit1, 6, 12);
                cdata.palette.palette[0] = 0x0d;
                cdata.palette.palette[1] = 0x30;
                cdata.tiledata = new byte[12];
                for (var i = 0; i < 12; i++)
                {
                    var line = new byte[8];//setLine函数，要求字节对齐
                    line[0] = 1;
                    cdata.SetLine(i, line);
                }
                //光标特别命名很独特
                bank.RegTileData("cursor", cdata);
            }
            //save map file
            //System.IO.File.WriteAllBytes("d:\\UTF16CONV", savemap.ToArray());

            Console.WriteLine("Load HZK12:" + charcount);
        }
    }
}
